%{

#include <math.h>
#include <stdio.h>

#define STR_LENGTH 300

char str[1000];

%}

%union {
	int ival;
	float fval;
	char * sval;
}

%type <sval> ID_ZMIENNEJ
%type <sval> typ
%type <sval> STALA_LOGICZNA
%type <sval> STALA_CALKOWITA
%type <sval> STALA_RZECZYWISTA
%type <sval> STALA_NAPIS

%type <sval> wykonanie
%type <sval> program
%type <sval> wypisz
%type <sval> przypisz
%type <sval> petla
%type <sval> stala
%type <sval> wyrazenie_warunkowe
%type <sval> neg_operator_logiczny
%type <sval> deklaracja_zmiennej
%type <sval> operator_matematyczny

%token NOWA_ZMIENNA 
%token TYP_LOGICZNA TYP_CALKOWITA TYP_RZECZYWISTA TYP_NAPIS
%token STALA_CALKOWITA STALA_RZECZYWISTA STALA_LOGICZNA STALA_NAPIS
%token START STOP
%token DLA DO ZROB KONIEC_DLA
%token JESLI JESLI_NIE
%token WYPISZ
%token ID_ZMIENNEJ 
%token PRZYPISANIE 
%token EQUAL NEQUAL WBR WIEKSZY MBR MNIEJSZY
%token MINUS PLUS DIV MULTI
%token L_NAWIAS P_NAWIAS
%token NOWA_LINIA

%left PLUS MINUS
%left DIV MULTI


%%
glowny_program : START wykonanie STOP { printf("& Glowny program.\n"); }
 ;

wykonanie: 
	| wykonanie program { printf("& wykonanie program:\n"); }
;


program: wyrazenie_warunkowe { printf("%s\n", $1); }
	| petla { printf("\n%s\n", $1); }
	| deklaracja_zmiennej { printf("%s\n", $1); }
	| wypisz { printf("%s\n", $1); }
	| przypisz { printf("%s\n", $1); }
;

petla: DLA ID_ZMIENNEJ PRZYPISANIE STALA_CALKOWITA DO STALA_CALKOWITA ZROB wypisz KONIEC_DLA {
	char result[3*STR_LENGTH];
	char helper[STR_LENGTH];
	sprintf(result, "int %s\n", $2+1);

	sprintf(helper, "beginfor:\n");
	strcat(result, helper);
	
	sprintf(helper, "cmp %s, licznik\n", $6);
	strcat(result, helper);
	
	sprintf(helper, "ifneql retval, exitfor\n");
	strcat(result, helper);
	
	sprintf(helper, "%s\n", $8);
	strcat(result, helper);
	
	sprintf(helper, "push licznik\nadd 1\nset licznik, retval\n");
	strcat(result, helper);

	sprintf(helper, "jmpif true beginfor:\nexitfor:\n");
	strcat(result, helper);
	$$ = strdup(result);
	}
;

wyrazenie_warunkowe: JESLI stala neg_operator_logiczny stala START wypisz STOP {
		char result[2*STR_LENGTH];
		sprintf(result, "%s %s, %s\njmpif retval, exitif:\n%s\nexitif:", $3, $2, $4, $2, $6);
		$$ = strdup(result);
	}
	| JESLI ID_ZMIENNEJ START wypisz STOP {
		char result[2*STR_LENGTH];
		sprintf(result, "jmpif %s, exitif:\n%s\nexitif:", $2+1, $4);
		$$ = strdup(result);
	}
;

deklaracja_zmiennej : NOWA_ZMIENNA typ ID_ZMIENNEJ {
		char result[STR_LENGTH];
		sprintf(result, "%s %s", $2, $3+1);
		$$ = strdup(result);
		}
	| NOWA_ZMIENNA typ ID_ZMIENNEJ PRZYPISANIE stala {
		char result[STR_LENGTH];
		sprintf(result, "%s %s\nset %s, %s", $2, $3+1, $3+1, $5);
		$$ = strdup(result);
	}
;

typ: TYP_LOGICZNA { $$ = "bool"; }
	| TYP_CALKOWITA { $$ = "int"; }
	| TYP_RZECZYWISTA { $$ = "float"; }
	| TYP_NAPIS { $$ = "string"; }
;

stala: STALA_RZECZYWISTA
	| STALA_CALKOWITA
	| STALA_LOGICZNA
	| STALA_NAPIS
;

operator_matematyczny : PLUS { $$ = "add"; }
	| MINUS { $$ = "subs"; }
	| DIV { $$ = "div"; }
	| MULTI { $$ = "multi"; }
;

wypisz: WYPISZ ID_ZMIENNEJ { 
	char result[STR_LENGTH];
	sprintf(result, "print %s", $2+1);
	$$ = strdup(result); }
;
wypisz: WYPISZ stala { 
	char result[STR_LENGTH];
	sprintf(result, "print %s", $2);
	$$ = strdup(result); }
;

przypisz: ID_ZMIENNEJ PRZYPISANIE ID_ZMIENNEJ {
		char result[STR_LENGTH];
		sprintf(result, "set %s, %s", $1+1, $3+1);
		$$ = result;
		}
	| ID_ZMIENNEJ PRZYPISANIE stala {
		char result[STR_LENGTH];
		sprintf(result, "set %s, %s", $1+1, $3);
		$$ = result;
		}
	| ID_ZMIENNEJ PRZYPISANIE stala operator_matematyczny stala {
		char result[STR_LENGTH];
		sprintf(result, "push %s\n%s %s\nset %s, retval",$3, $4, $5, $1+1);
		$$ = result;
		}
;

neg_operator_logiczny : EQUAL { $$ = "neql"; }
	| NEQUAL { $$ = "eql"; }
	| WBR { $$ = "ncmp"; }
	| WIEKSZY { $$ = "leql"; }
	| MBR { $$ = "cmp"; }
;

%%
#include "PPPskaner.lex.c"

int yyerror(char *s) {
  printf("PARSER FAIL: \"%s\"\n", s);
}

main(){
  yyparse();
  printf("\n\nPrzerobionych linii: %02d\n", line_no);
}
